package com.youlai.boot.system.service.impl;

import cn.hutool.core.io.resource.ClassPathResource;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.UnitValue;
import com.youlai.boot.system.enums.RecycleStatusEnum;
import com.youlai.boot.system.mapper.RecycleRequestMapper;
import com.youlai.boot.system.mapper.RequestWasteMapper;
import com.youlai.boot.system.mapper.WasteTypeMapper;
import com.youlai.boot.system.model.entity.RecycleRequest;
import com.youlai.boot.system.model.entity.RequestWaste;
import com.youlai.boot.system.model.entity.WasteType;
import com.youlai.boot.system.model.vo.ReportData;
import com.youlai.boot.system.service.ReportService;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.io.OutputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ReportServiceImpl implements ReportService {

    @Resource
    private RecycleRequestMapper recycleRequestMapper;

    @Resource
    private RequestWasteMapper requestWasteMapper;

    @Resource
    private WasteTypeMapper wasteTypeMapper;

    private PdfFont pdfFont;

    private void initPdfFont(PdfDocument pdf) {
        try {
            ClassPathResource fontResource = new ClassPathResource("static/fonts/LXGWWenKai-Light.ttf");
            pdfFont = PdfFontFactory.createFont(fontResource.getPath(), PdfEncodings.IDENTITY_H, pdf);
        } catch (Exception e) {
            throw new RuntimeException("初始化PDF字体失败", e);
        }
    }

    @Override
    public void generatePdfReport(LocalDate startDate, LocalDate endDate, OutputStream outputStream) {
        try {

            PdfDocument pdf = new PdfDocument(new PdfWriter(outputStream));
            initPdfFont(pdf);

            Document document = new Document(pdf);

            // 添加标题
            document.add(new Paragraph("垃圾回收统计报告")
                    .setTextAlignment(com.itextpdf.layout.properties.TextAlignment.CENTER)
                    .setFont(pdfFont)
                    .setFontSize(18)
                    .setBold()
                    .setMarginBottom(15));

            // 添加时间段
            document.add(new Paragraph(String.format("报告期间：%s 至 %s",
                    startDate.format(DateTimeFormatter.ISO_LOCAL_DATE),
                    endDate.format(DateTimeFormatter.ISO_LOCAL_DATE)))
                    .setFont(pdfFont)
                    .setFontSize(12)
                    .setTextAlignment(com.itextpdf.layout.properties.TextAlignment.CENTER)
                    .setMarginBottom(20));

            // 获取报告数据
            ReportData reportData = getReportData(startDate, endDate);

            // 添加总回收量
            document.add(new Paragraph("总回收量: " + reportData.getTotalRecycled() + " kg")
                    .setFont(pdfFont)
                    .setFontSize(14)
                    .setBold()
                    .setMarginBottom(5));

            // 添加总碳减排量
            document.add(new Paragraph("总碳减排量: " + reportData.getTotalCarbonReduction() + " kg")
                    .setFont(pdfFont)
                    .setFontSize(14)
                    .setBold()
                    .setMarginBottom(5));

            // 添加回收订单总数
            document.add(new Paragraph("回收订单总数: " + reportData.getTotalOrders() + " 笔")
                    .setFont(pdfFont)
                    .setFontSize(14)
                    .setBold()
                    .setMarginBottom(15));

            // 添加各类废物回收量表格
            addWasteTypeTable(document, reportData.getWasteTypeData());

            document.close();
        } catch (Exception e) {
            throw new RuntimeException("生成PDF报告失败", e);
        }
    }

    @Override
    public ReportData getReportData(LocalDate startDate, LocalDate endDate) {
        ReportData reportData = new ReportData();
        reportData.setTitle("废物回收统计报告");
        reportData.setPeriod(String.format("%s 至 %s",
                startDate.format(DateTimeFormatter.ISO_LOCAL_DATE),
                endDate.format(DateTimeFormatter.ISO_LOCAL_DATE)));

        // 查询指定时间段内已完成的回收请求
        List<RecycleRequest> finishedRequests = recycleRequestMapper.selectList(
                new LambdaQueryWrapper<RecycleRequest>()
                        .between(RecycleRequest::getCreateTime, startDate, endDate)
                        .eq(RecycleRequest::getStatus, RecycleStatusEnum.RECYCLED.getCode()));

        // 设置回收订单总数
        reportData.setTotalOrders(finishedRequests.size());

        // 获取所有已完成请求的ID
        List<Long> requestIds = finishedRequests.stream()
                .map(RecycleRequest::getId)
                .collect(Collectors.toList());

        // 查询这些请求对应的废品回收记录
        List<RequestWaste> allWastes = new ArrayList<>();
        if (!requestIds.isEmpty()) {
            allWastes = requestWasteMapper.selectList(
                    new LambdaQueryWrapper<RequestWaste>()
                            .in(RequestWaste::getRequestId, requestIds));
        }

        // 获取所有废品类型信息
        Map<Long, WasteType> wasteTypeMap = wasteTypeMapper.selectList(null).stream()
                .collect(Collectors.toMap(WasteType::getId, wasteType -> wasteType));

        // 按废品类型分组统计
        Map<Long, List<RequestWaste>> wastesByType = allWastes.stream()
                .collect(Collectors.groupingBy(RequestWaste::getTypeId));

        // 计算总回收量和总碳减排量
        BigDecimal totalRecycled = BigDecimal.ZERO;
        BigDecimal totalCarbonReduction = BigDecimal.ZERO;
        List<ReportData.WasteTypeData> wasteTypeDataList = new ArrayList<>();

        for (Map.Entry<Long, List<RequestWaste>> entry : wastesByType.entrySet()) {
            Long typeId = entry.getKey();
            List<RequestWaste> wastes = entry.getValue();
            WasteType wasteType = wasteTypeMap.get(typeId);

            if (wasteType != null) {
                // 计算该类型的总重量
                BigDecimal typeWeight = wastes.stream()
                        .map(RequestWaste::getWeight)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);

                // 计算该类型的碳减排量（根据废品类型的碳减排系数计算）
                BigDecimal typeCarbonReduction = typeWeight.multiply(wasteType.getCerc())
                        .multiply(new BigDecimal("0.001")); // 转换为吨

                // 累加总量
                totalRecycled = totalRecycled.add(typeWeight);
                totalCarbonReduction = totalCarbonReduction.add(typeCarbonReduction);

                // 添加类型统计数据
                ReportData.WasteTypeData typeData = new ReportData.WasteTypeData();
                typeData.setWasteType(wasteType.getTypeName());
                typeData.setAmount(typeWeight);
                typeData.setCarbonReduction(typeCarbonReduction);
                wasteTypeDataList.add(typeData);
            }
        }

        reportData.setTotalRecycled(totalRecycled);
        reportData.setTotalCarbonReduction(totalCarbonReduction);
        reportData.setWasteTypeData(wasteTypeDataList);

        return reportData;
    }

    /**
     * PDF添加各类废物回收量表格
     * 
     * @param document
     * @param wasteTypeData
     */
    private void addWasteTypeTable(Document document, List<ReportData.WasteTypeData> wasteTypeData) {
        // 创建表格并设置样式
        Table table = new Table(3);
        table.setWidth(UnitValue.createPercentValue(100));
        table.setMarginTop(10);
        table.setMarginBottom(20);

        // 添加表头
        Cell header1 = new Cell().add(new Paragraph("废物类型").setFont(pdfFont).setBold());
        Cell header2 = new Cell().add(new Paragraph("回收量(kg)").setFont(pdfFont).setBold());
        Cell header3 = new Cell().add(new Paragraph("碳减排量(kg)").setFont(pdfFont).setBold());
        table.addHeaderCell(header1);
        table.addHeaderCell(header2);
        table.addHeaderCell(header3);

        // 添加数据行
        for (ReportData.WasteTypeData data : wasteTypeData) {
            table.addCell(new Cell().add(new Paragraph(data.getWasteType()).setFont(pdfFont)));
            table.addCell(new Cell().add(new Paragraph(data.getAmount().toString()).setFont(pdfFont)));
            table.addCell(new Cell().add(new Paragraph(data.getCarbonReduction().toString()).setFont(pdfFont)));
        }

        document.add(table);
    }
}